package com.atguigu.guli.service.trade.controller.api;

import com.atguigu.guli.common.util.HttpClientUtils;
import com.atguigu.guli.common.util.StreamUtils;
import com.atguigu.guli.service.base.exception.GuliException;
import com.atguigu.guli.service.base.result.R;
import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.trade.entity.Order;
import com.atguigu.guli.service.trade.service.OrderService;
import com.atguigu.guli.service.trade.service.WeixinPayService;
import com.atguigu.guli.service.trade.util.WeixinPayProperties;
import com.github.wxpay.sdk.WXPayUtil;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author dyqstart
 * @create 2021-07-19-18:55
 * @since 1.0.0
 */
//@CrossOrigin
@RestController
@RequestMapping("/api/trade/weixin-pay")
@Api(tags = "网站微信支付")
@Slf4j
public class ApiWeixinPayController {

    @Autowired
    private WeixinPayService weixinPayService;

    @Autowired
    private WeixinPayProperties weixinPayProperties;

    @Autowired
    private OrderService orderService;


    @GetMapping("create-native/{orderNo}")
    public R createNative(@PathVariable String orderNo, HttpServletRequest request){

        String remoteAddr = request.getRemoteAddr();
        Map map = weixinPayService.createNative(orderNo, remoteAddr);
        return R.ok().data(map);
    }

    @PostMapping("callback/notify")
    public String wxNotify(HttpServletRequest request){


        try {
            System.out.println("微信发送的回调");
            ServletInputStream inputStream = request.getInputStream();
            String notifyXml = StreamUtils.inputStream2String(inputStream , "utf-8");
            System.out.println("notifyXml = " + notifyXml);

            //校验签名
            if (WXPayUtil.isSignatureValid(notifyXml, weixinPayProperties.getPartnerKey())){

                System.out.println("验签成功");
                //验签成功，执行下一步

                //解析xml数据
                Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml);

                //判断通信和业务是否成功
                if ("SUCCESS".equals(notifyMap.get("return_code")) && "SUCCESS".equals(notifyMap.get("result_code"))){
                    //通信和业务成功
                    //获取商户订单号
                    String orderNo = notifyMap.get("out_trade_no");
                    //根据订单号获取商户订单数据
                    Order order = orderService.getOrderByOrderNo(orderNo);
                    //并校验返回的订单金额是否与商户侧的订单金额一致
                    if (order != null && order.getTotalFee() == Long.parseLong(notifyMap.get("total_fee"))){
                        //幂等性：无论接口被调用多少次，产生的结果是一致的
                        //接口调用的幂等性原则（保持接口调用的幂等性）
                        //首先检查订单状态（目的：防止应答微信端没有及时收到）
                        synchronized (this){//分布式项目使用redis分布式锁
                            if (order.getStatus() == 0){
                                //修改订单状态 记录支付日志
                                orderService.updateOrderStatus(notifyMap);
                                //将用户现有代金券减1
                            }

                        }
                        HashMap<String, String> returnMap = new HashMap<>();
                        returnMap.put("return_code","SUCCESS");
                        returnMap.put("result_msg","成功");
                        String returnXml = WXPayUtil.mapToXml(returnMap);
                        System.out.println("支付成功，已应答");
                        return returnXml;
                    }else{
                        //告警通知
                        //记录日志，为系统管理员发送短信，站内信
                        log.error("金额不一致，告警");
                    }
                }
            }else {
                //告警通知
                //记录日志，为系统管理员发送短信，站内信
                log.error("验签失败，告警");
            }

            HashMap<String, String> returnMap = new HashMap<>();
            returnMap.put("return_code","FAIL");
            returnMap.put("result_msg","失败");
            String returnXml = WXPayUtil.mapToXml(returnMap);
            System.out.println("支付失败，已应答");
            return returnXml;

        } catch (Exception e) {
            throw new GuliException(ResultCodeEnum.CALLBACK_ERROR);
        }
    }

    /**
     * 获取沙箱密钥
     * @return
     * @throws Exception
     */
    @GetMapping("get-sign-key")
    public R getSignKey() throws Exception {
        //调用微信api接口
        HttpClientUtils clientUtils = new HttpClientUtils(weixinPayProperties.getUrl());
        //组装接口参数
        HashMap<String, String> params = new HashMap<>();
        params.put("mch_id", weixinPayProperties.getPartner());//商户号
        params.put("nonce_str",WXPayUtil.generateNonceStr());//生成随机字符串

        //将参数转换成xml字符串格式，生成带有签名的xml格式字符串
        String xmlParams = WXPayUtil.generateSignedXml(params, weixinPayProperties.getPartnerKey());
        clientUtils.setXmlParam(xmlParams);//将参数放入请求对象的方法体
        clientUtils.setHttps(true);//使用https形式发送
        clientUtils.post();//发送post请求
        String content = clientUtils.getContent();//得到响应结果
        return R.ok().data("content",content);

    }

}
